﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Contexts;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using System.Web;
using Guitar.Comet.Message;
using Microsoft.AspNet.SignalR;
using Newtonsoft.Json;
using Timer = System.Timers.Timer;
using XL.Framework.Domain.Core.Repository;

namespace Guitar.Comet.Host
{
    public class GuitarCometService : Hub
    {
        /// <summary>
        /// 队列消息 
        /// </summary>
        private static readonly Queue<MessageEnvelope> Messages = new Queue<MessageEnvelope>();

        /// <summary>
        /// 定时器
        /// </summary>
        private static readonly Timer Timer = new Timer(2 * 1000);

        /// <summary>
        /// 并发锁
        /// </summary>
        private static readonly object LockObject = new object();

        /// <summary>
        /// 客户端记录缓存
        /// </summary>
        private static readonly Dictionary<string, string> AppClients = new Dictionary<string, string>();

        private static readonly ICommandRepository<MessageEnvelope> MessagesRepository = new MessagesRepository();

        private static readonly ICommandRepository<Application> CommandApplicationRepository = new ApplicationRepository();
        private static readonly IQueryRepository<Application> QueryApplicationRepository = new ApplicationRepository();

        /// <summary>
        /// 客户端建立连接时
        /// </summary>
        /// <returns></returns>
        public override Task OnConnected()
        {
            string clientName = Context.QueryString["ClientName"];
            RemoveClient(clientName);
            AddClient(clientName);
            if (!Timer.Enabled)
            {
                Timer.Start();
                Timer.Elapsed += _timer_Elapsed;
            }

            return base.OnConnected();
        }

        private void AddClient(string clientName)
        {
            AppClients.Add(clientName, Context.ConnectionId);
            CommandApplicationRepository.Add(new Application() { ClientName = clientName, ConnectionID = Context.ConnectionId, _id = Context.ConnectionId });

        }

        private void RemoveClient(string clientName)
        {
            if (AppClients.ContainsKey(clientName))
                AppClients.Remove(clientName);

            var applicationClient = QueryApplicationRepository.GetSingle(p => p.ClientName == clientName);
            if (applicationClient != null)
                CommandApplicationRepository.Remove(applicationClient);
        }

        /// <summary>
        /// 客户端断开连接时
        /// </summary>
        /// <param name="stopCalled"></param>
        /// <returns></returns>
        public override Task OnDisconnected(bool stopCalled)
        {
            Task.Factory.StartNew(() =>
            {
                var clientName = Context.QueryString["ClientName"];
                RemoveClient(clientName);
            });
            return base.OnDisconnected(stopCalled);
        }

        void _timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            lock (LockObject)
            {
                Timer.Stop();

                if (Messages.Count == 0)
                {
                    Thread.Sleep(50);
                    Timer.Start();
                    return;
                }

                var popMessage = Messages.Dequeue();

                if (popMessage.Expire.Subtract(DateTime.Now).Milliseconds <= 0)
                {
                    // 转为死信
                }
                else
                {
                    string connectionID;
                    AppClients.TryGetValue(popMessage.ToClientName, out connectionID);
                    if (string.IsNullOrEmpty(connectionID))
                    {
                        Messages.Enqueue(popMessage);
                    }
                    else
                    {
                        WhenClienTaskServiceHandler(connectionID, popMessage);
                    }
                }
                Thread.Sleep(50);
                Timer.Start();
            }
        }

        /// <summary>
        /// 将消息推送至指定的客户端
        /// </summary>
        /// <param name="connectionID">客户端唯一标识ID</param>
        /// <param name="message">消息体</param>
        /// <returns>异步task</returns>
        private async Task WhenClienTaskServiceHandler(string connectionID, MessageEnvelope message)
        {
            string json = JsonConvert.SerializeObject(message);
            await Clients.Client(connectionID).ClientHandle(json);
        }

        /// <summary>
        /// 服务端主函数入口
        /// </summary>
        /// <param name="json"></param>
        public void ServiceHandler(string json)
        {
            var message = JsonConvert.DeserializeObject<MessageEnvelope>(json);
            Messages.Enqueue(message);

            // 异步写磁盘
            Task.Factory.StartNew(() =>
            {
                MessagesRepository.Add(message);
            });
        }
    }
}